﻿// 
//    Copyright 2010 The JaernCloud Project
// 
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
// 
//        http://www.apache.org/licenses/LICENSE-2.0
// 
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
// 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JaernCloud.Language.Compiler.Types;
using System.Linq.Expressions;
using System.Dynamic;

namespace JaernCloud.Language.Runtime {
    
    /// <summary>
    /// Represents an identifier object.
    /// The primary focus in the identifier is the InheritsFrom members that it makes available in a scope as an identifier.
    /// </summary>
    public class IdentifierNodeObject : NodeObject<INodeType>, INodeObjectValueHolder {

        public override string ToString() {
            StringBuilder sb = new StringBuilder(base.ToString()).Append(" : ");
            const string separator = ", ";
            foreach (INodeObject<INodeType> nodeObject in InheritsFrom) {
                sb.Append(nodeObject.ToString()).Append(separator);
            }
            if (InheritsFrom.Any()) {
                sb.Length -= separator.Length;
            }
            return sb.ToString();
        }

        public IHasValueHolder ValueHolder {
            get {
                foreach (var inherited in InheritsFrom) {
                    if (inherited is IHasValueHolder) {
                        return inherited as IHasValueHolder;
                    }
                }
                return null;
            }
        }

        public override INodeObject<INodeType> FromType(INodeType nodeType, INodeObjectGenerator objectGenerator) {
            return new IdentifierNodeObject { _type = nodeType, _objectGenerator = objectGenerator };
        }

        #region Dynamic Object        

        public override bool TryConvert(System.Dynamic.ConvertBinder binder, out object result) {
            foreach (var inherited in InheritsFrom) {
                if (inherited is DynamicObject) {
                    DynamicObject dynObj = inherited as DynamicObject;
                    if(dynObj.TryConvert(binder, out result)) {
                        return true;
                    }
                }
            }
            return base.TryConvert(binder, out result);
        }

        public override bool TryUnaryOperation(UnaryOperationBinder binder, out object result) {
            foreach (var inherited in InheritsFrom) {
                if (inherited is DynamicObject) {
                    DynamicObject dynObj = inherited as DynamicObject;
                    if (dynObj.TryUnaryOperation(binder, out result)) {
                        return true;
                    }
                }
            }
            return base.TryUnaryOperation(binder, out result);
        }

        public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result) {
            foreach (var inherited in InheritsFrom) {
                if (inherited is DynamicObject) {
                    DynamicObject dynObj = inherited as DynamicObject;
                    if (dynObj.TryBinaryOperation(binder, arg, out result)) {
                        return true;
                    }
                }
            }
            return base.TryBinaryOperation(binder, arg, out result);
        }

        public override bool TrySetMember(SetMemberBinder binder, object value) {
            foreach (var inherited in InheritsFrom) {
                if (inherited is DynamicObject) {
                    DynamicObject dynObj = inherited as DynamicObject;
                    if (dynObj.TrySetMember(binder, value)) {
                        return true;
                    }
                }
            }
            return base.TrySetMember(binder, value);
        }

        #endregion

    }
}
